package com.zsguan.s.stools4andr.os;

import android.os.Environment;
import android.os.Handler;
import android.os.Message;

import com.zsguan.s.stools4andr.STextTool;
import com.zsguan.s.stools4andr.io.ZFileManager;
import com.zsguan.s.stools4andr.io.ZFileReadManager;
import com.zsguan.z.slogger4andr.ZLogger;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by Administrator on 2015/9/14.
 * 文件改变管理器
 */
public class ZFileScanTask {

    private static final String SPLIT = "&z;";

    private boolean isStop = false;
    private boolean isRunning = false;

    private boolean isInit = true;

    private String mCachePath;
    // 待扫描目录
    private String mScanPath;
    // 缓存
    private Map<String, FileBean> mFileBeanMap;
    private int count = 0; // 文件总数量

    private Handler mHandler;
    private OnFilterListener mFilterListener;

    public ZFileScanTask(Handler handler) {
        this(Environment.getExternalStorageDirectory().getAbsolutePath(), handler);
    }

    public ZFileScanTask(String scanPath, Handler handler) {
        this.mScanPath = scanPath;
        this.mFileBeanMap = new HashMap<>(16 * 1024);
        this.mHandler = handler;

        this.mCachePath = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "scan.txt";
    }

    public void setmFilterListener(OnFilterListener filterListener) {
        this.mFilterListener = filterListener;
    }

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                if (isInit) {
                    sendMessage(-1, null);

                    isInit = readData4Cache(); // 有缓存表示已初始化

                    try {
                        ZFileManager.clear(mCachePath);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

                count = 0;
                isRunning = true;
                sendMessage(0, null);
                scan(mScanPath);
                sendMessage(1, String.valueOf(count));
                isInit = false;
                isRunning = false;
            }
        }).start();
    }

    public void stop() {
        isStop = true;
    }

    public void clear() {
        mFileBeanMap.clear();
        isInit = true;
    }

    public boolean isRunning() {
        return isRunning;
    }

    private void scan(String path) {
        if (STextTool.isEmpty(path) || isStop ||  mCachePath.equals(path) || (null != mFilterListener && !mFilterListener.onFilter(path))) {
            return;
        }

        count++;

        File file = new File(path);

        FileBean fb = new FileBean();
        fb.parent = file.getParent();
        fb.path = path;
        fb.size = file.length();

        loadFile2Cache(fb);
        writeMessage2File(fb);

        if (file.isDirectory()) {
            File[] files = file.listFiles();

            if (null != files && 0 != files.length) {
                for (File ver0 : files) {
                    scan(ver0.getAbsolutePath());
                }
            }
        }
    }

    private void loadFile2Cache(FileBean fb) {
        if (mFileBeanMap.containsKey(fb.path)) {
            if (!mFileBeanMap.containsValue(fb)) {
                fb.event = FileBean.MODIFY;

                if (!isInit) {
                    ZLogger.i("Modify: " + fb.path);
                    sendAndWriteMessage(fb);
                }
            }
        } else {
            fb.event = FileBean.CREATE;

            if (!isInit) {
                ZLogger.i("Create: " + fb.path);
                sendAndWriteMessage(fb);
            }
        }

        mFileBeanMap.put(fb.path, fb);
    }

    private void sendAndWriteMessage(FileBean bean) {
//        writeMessage2File(bean);
        sendMessage(bean.event, bean.path);
    }

    private void sendMessage(int what, String msg) {
        if (null == msg) {
            mHandler.sendEmptyMessage(what);
        } else {
            Message message = Message.obtain();
            message.what = what;
            message.obj = msg;

            mHandler.sendMessage(message);
        }
    }

    private void writeMessage2File(FileBean bean) {
        try {
            ZFileManager.write(mCachePath, getCacheLine(bean));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从缓存中读取上次保存的记录
     *
     * @return 返回是否存在缓存记录
     */
    private boolean readData4Cache() {
        try {
            return ZFileManager.read(mCachePath, new ZFileReadManager.OnReadLineListener() {
                @Override
                public void onReadLine(String line) throws UnsupportedEncodingException {
                    FileBean fb = getFileBean(line);

                    mFileBeanMap.put(fb.path, fb);
                }
            });
        } catch (FileNotFoundException e) {
            return false;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return false;
    }

    private String getCacheLine(FileBean bean) {
        if (null == bean) {
            return "";
        }

        return "parent:" + bean.parent + SPLIT + "path:" + bean.path + SPLIT + "size:" + bean.size + SPLIT + "event:" + bean.event + "\r\n";
    }

    private FileBean getFileBean(String cacheLine) {
        FileBean fb = new FileBean();

        String[] fs = cacheLine.split(SPLIT);

        for (String f : fs) {
            String[] kv = f.split(":");

            String k = kv[0];
            String v = kv[1];

            if ("parent".equals(k)) {
                fb.parent = v;
            } else if ("path".equals(k)) {
                fb.path = v;
            } else if ("size".equals(k)) {
                fb.size = Long.valueOf(v);
            } else if ("event".equals(k)) {
                fb.event = Integer.valueOf(v);
            }
        }

        return fb;
    }

    class FileBean {
        public static final int MODIFY = 101;
        public static final int CREATE = 102;
        public static final int NONE = 103;

        public String parent;
        public String path;
        public long size;
        public int event = NONE;

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;

            FileBean fileBean = (FileBean) o;

            return size == fileBean.size && !(path != null ? !path.equals(fileBean.path) : fileBean.path != null);
        }

        @Override
        public int hashCode() {
            int result = path != null ? path.hashCode() : 0;
            result = 31 * result + (int) (size ^ (size >>> 32));
            return result;
        }

        @Override
        public String toString() {
            return "FileBean{" +
                    "parent='" + parent + '\'' +
                    ", path='" + path + '\'' +
                    ", size=" + size +
                    ", event=" + event +
                    '}';
        }
    }

    public interface OnFilterListener {
        /**
         * 筛选需要匹配的文件
         * @param path 文件路径
         * @return 匹配结果  true表示需要匹配  false表示不需要匹配
         */
        boolean onFilter(String path);
    }
}
